﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;

namespace GetUsers
{
    class Program
    {
        private static TfsConfigurationServer server=null;
        private static IIdentityManagementService ims=null;
        private static ISecurityService ssc = null;
        static void Main(string[] args)
        {
            //Test Cases
            //args=new String[] {"/server:http://lucky-bpartm004:8080/tfs"};
            //args = new String[] { "/collection:http://lucky-bpartm004:8080/tfs/defaultcollection"};
            try
            {
                switch (HandleArgs(args))
                {
                    case 1: //server level + all collection level user information                        
                        EnumServerGroups(new Uri(args[0].Substring(8)), true);                        
                        break;
                    case 2: //server level
                        EnumServerGroups(new Uri(args[0].Substring(8)), false);
                        break;
                    case 3: //specific collection level        
                        Console.WriteLine();
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine("<<< Group Membership for Team Project Collection --- {0} ---  >>>", args[0].Substring(12));
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine();
                        EnumCollectionGroups(new Uri(args[0].Substring(12)));
                        break;
                    default: //error
                        SyntaxError();                        
                        Environment.Exit(0);
                        break;
                }
            }
            catch (Exception e )
            {
                Console.WriteLine(e.Message + "\n" + e.InnerException);                
            }       
            
        }

        /// <summary>
        /// Parses input args
        /// </summary>
        /// <param name="args"></param>
        /// <returns>
        /// 0 failure
        /// 1 server + collection
        /// 2 server only
        /// 3 specific collection
        /// </returns>
        private static int HandleArgs(string[] args)
        {
            try
            {
                if (args.Length == 0)
                {                    
                    return 0;
                }
                else if(args[0].ToLower().StartsWith(@"/server:http"))
                {
                    switch (args.Length>1?args[1].ToLower():null)
                    {
                        case "/serveronly":
                            return 2;                                                        
                        case "/all":
                            return 1;                                                   
                        default:
                            if (args.Length == 1)
                            {
                                return 1;
                            }
                            return 0;
                    }            
                    
                }
                else if (args[0].ToLower().StartsWith(@"/collection:http"))
                {
                    return 3;
                }
                else
                {                    
                    return 0;                    
                }                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message + "\n" + e.InnerException);
                throw e;
            }

        }

        private static int EnumGroups(TeamFoundationIdentity id, int count)
        {
            Console.WriteLine(new String('-', 2 * count) + "[G] " + id.DisplayName + " TfsID:" + id.TeamFoundationId.ToString());
            for (int i = 0; i < id.Members.Length; i++)
            {
                TeamFoundationIdentity newId = ims.ReadIdentity(id.Members[i], MembershipQuery.Direct, ReadIdentityOptions.None);
                
                if (newId.IsContainer)
                {
                    
                    count++;
                    EnumGroups(newId, count);
                    count--;
                    continue;
                }
                Console.WriteLine(new String('-', 2 * (count + 1)) + newId.DisplayName + " " + id.TeamFoundationId.ToString());             
            }
            //Console.ReadKey();
            return count;
        }

        private static void SyntaxError()
        {
            Console.WriteLine("Incorrect Syntax");
            Console.WriteLine("Usage: GetUsers /{Server|Collection}:Uri [/{All|ServerOnly}]");
            
        }

        private static void EnumServerGroups(Uri serverUri, bool AllFlag)
        {
            try
            {
                server = new TfsConfigurationServer(serverUri);
                server.EnsureAuthenticated();
                if (server.HasAuthenticated)
                {
                    ssc = server.GetService<ISecurityService>();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine(new String('=', 40));
                    Console.WriteLine(new String('=', 40));
                    Console.WriteLine("<<< Instance Level Group Memmberships >>>");
                    Console.WriteLine(new String('=', 40));
                    Console.WriteLine(new String('=', 40));
                    Console.WriteLine();
                    List<TeamFoundationIdentity> ids = new List<TeamFoundationIdentity>();

                    TeamFoundationIdentity tfid = null;

                    ims = server.GetService<IIdentityManagementService>();

                    ids.AddRange(ims.ListApplicationGroups(null, ReadIdentityOptions.IncludeReadFromSource));
                    foreach (TeamFoundationIdentity id in ids)
                    {
                        tfid = ims.ReadIdentity(id.Descriptor, MembershipQuery.Direct, ReadIdentityOptions.None);
                        EnumGroups(tfid, 0);
                    }
                    if (AllFlag == true)
                    {
                        Console.WriteLine();
                        Console.WriteLine();
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine("<<< Team Project Collection Level Group Memberships  >>>");
                        Console.WriteLine(new String('=', 40));
                        Console.WriteLine(new String('=', 40));
                        ITeamProjectCollectionService tpcSvc = server.GetService<ITeamProjectCollectionService>();
                        foreach (TeamProjectCollection tpc in tpcSvc.GetCollections())
                        {
                            EnumCollectionGroups(tpc);
                        }
                        
                    }
                }

            }
            catch (Exception e)
            {               
                throw e;
            }
            
        }

        private static void EnumCollectionGroups(Uri collectionUri)
        {            
            try
            {
                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(collectionUri);
                tpc.EnsureAuthenticated();

                if (tpc.HasAuthenticated)
                {                    
                    ims = tpc.GetService<IIdentityManagementService>();
                    List<TeamFoundationIdentity> ids = new List<TeamFoundationIdentity>();
                    ids.AddRange(ims.ListApplicationGroups(null, ReadIdentityOptions.TrueSid));
                    TeamFoundationIdentity tfid = null;
                    foreach (TeamFoundationIdentity id in ids)
                    {
                        tfid = ims.ReadIdentity(id.Descriptor, MembershipQuery.Direct, ReadIdentityOptions.None);
                        EnumGroups(tfid, 0);
                    }
                }

            }
            catch (Exception e)
            {

                throw e;
            }
        }

        private static void EnumCollectionGroups(TeamProjectCollection tpc)
        {
            try
            {
                Console.WriteLine();
                Console.WriteLine(new String('=', 40));
                Console.WriteLine("<<< Group Membership for Team Project Collection --- {0} ---  >>>", tpc.Name);
                Console.WriteLine(new String('=', 40));
                if (tpc.State == TeamFoundationServiceHostStatus.Started)
                {
                    EnumCollectionGroups(new Uri(server.Uri.ToString() + "/" + tpc.Name));
                }
                else
                    Console.WriteLine("Cannot read collection information since it is not online");
            }
            catch (Exception e)
            {                
                throw e;
            }
        }
    }
}
